<template>
  <ul class="hv-designer-layer-panel-tree-ul">
    <li v-for="(comp, index) in treeData" :key="comp.id">
      <a-dropdown :trigger="['contextmenu']">
        <div>
          <div
            class="hv-designer-layer-panel-move-item"
            @drop="moveDrop($event, comp, index, true)"
            @dragenter="moveDragEnter($event, comp, index, true)"
            @dragleave="moveDragLeave($event)"
            @dragover.prevent
          ></div>
          <div
            :class="['hv-designer-layer-panel-item']"
            :draggable="true"
            @dragstart="dragstart($event, comp, index)"
            @drop="drop($event, comp)"
            @mouseleave="editLabelInputToggle(comp, false)"
            @dragover.prevent
          >
            <div class="hv-designer-layer-panel-checked">
              <span @contextmenu.prevent.stop>
                <a-checkbox
                  v-model:checked="comp.checked"
                  @change="checkboxChange(comp)"
                />
              </span>
            </div>
            <div
              class="hv-designer-layer-panel-preview"
              :style="{ 'margin-left': level * 15 + 'px' }"
            >
              <img :src="comp.img" />
            </div>
            <div class="hv-designer-layer-panel-info" :style="layerPanelInfoStyle(comp)">
              <div class="hv-designer-layer-panel-header">
                <div
                  class="hv-designer-layer-panel-label"
                  :style="layerPanelInfoStyle(comp)"
                  @dblclick="editLabelInputToggle(comp, true)"
                >
                  <a-input
                    v-model:value="comp.label"
                    size="small"
                    v-if="
                      comp.id !== layerTreeRootNodeId &&
                      comp.unstructuredData &&
                      comp.unstructuredData.isEditLabel
                    "
                    v-hv-focus="{ selectTxt: true }"
                  />
                  <span v-else :title="comp.label">
                    {{ comp.label }}
                  </span>
                </div>
                <div
                  class="hv-designer-layer-panel-arrow"
                  v-if="
                    comp.id !== layerTreeRootNodeId &&
                    comp.type === layerTreeNodeType.group
                  "
                >
                  <span @click="comp.open = !comp.open" @contextmenu.prevent.stop>
                    <hv-dynamic-icon
                      :iconName="comp.open ? 'DownOutlined' : 'LeftOutlined'"
                    />
                  </span>
                </div>
              </div>
            </div>
          </div>
          <div
            class="hv-designer-layer-panel-move-item"
            @drop="moveDrop($event, comp, index, false)"
            @dragenter="moveDragEnter($event, comp, index, false)"
            @dragleave="moveDragLeave($event)"
            @dragover.prevent
          ></div>
        </div>
        <template #overlay>
          <a-menu @click="contextmenuClick($event, comp)">
            <a-menu-item
              key="addLayerGroup"
              v-if="comp.type === layerTreeNodeType.group && comp.level < maxLevel - 1"
            >
              <hv-dynamic-icon :iconName="'FolderOutlined'" /> 添加图层组
            </a-menu-item>

            <a-menu-item
              key="layerActive"
              v-if="comp.id !== layerTreeRootNodeId && comp.level === 1"
            >
              <hv-dynamic-icon :iconName="'SelectOutlined'" /> 激活图层
            </a-menu-item>

            <template v-if="comp.id !== layerTreeRootNodeId">
              <a-menu-item key="layerCopy">
                <hv-dynamic-icon :iconName="'CopyOutlined'" /> 复制图层
              </a-menu-item>

              <a-menu-item key="layerDown">
                <hv-dynamic-icon :iconName="'ArrowUpOutlined'" /> 置为上一层
              </a-menu-item>
              <a-menu-item key="layerUp">
                <hv-dynamic-icon :iconName="'ArrowDownOutlined'" /> 置为下一层
              </a-menu-item>

              <a-menu-item key="layerToTop">
                <hv-dynamic-icon :iconName="'ArrowUpOutlined'" /> 置为顶层
              </a-menu-item>

              <a-menu-item key="layerToBottom">
                <hv-dynamic-icon :iconName="'ArrowDownOutlined'" /> 置为底层
              </a-menu-item>
            </template>
          </a-menu>
        </template>
      </a-dropdown>

      <designer-layer-panel-node
        :treeData="comp.children"
        :level="level + 1"
        v-if="comp && comp.children && comp.open"
      />
    </li>
  </ul>
</template>

<script lang="ts">
import { defineComponent, type PropType, ref } from "vue";
import { cloneDeep } from "lodash";
import { layerPanelConfig } from "@/visual/configs/dashboard-conifg";
import { useDashboardStore } from "@/visual/stores/dashboard";
import DashboardEvent from "@/visual/events/dashboard-event";
import CommonUtil from "@/visual/commons/utils/common-util";

export default defineComponent({
  name: "DesignerLayerPanelNode",
  props: {
    treeData: {
      type: Array as PropType<any[]>,
      default: () => [],
    },
    level: {
      type: Number,
      default: 1,
    },
  },
  setup(props) {
    const useDashboard = useDashboardStore();

    const layerTreeNodeType = ref<any>(layerPanelConfig.layerTreeNodeType);
    const layerTreeRootNodeId = ref<any>(layerPanelConfig.layerTreeRootNodeId);
    const maxLevel = ref<any>(layerPanelConfig.maxLevel);

    const layerPanelInfoStyle = (comp: any) => {
      const baseWidth = comp.type === layerTreeNodeType.value.group ? "90px" : "90px";
      return {
        width: `calc(var(--hv-dash-des-config-panel-width) - ${
          props.level * 15
        }px - ${baseWidth}`,
      };
    };

    /**
     * 拖动开始
     */
    const dragstart = (e: any, dragComp: any, index: number) => {
      e.dataTransfer.setData("dragComp", JSON.stringify(dragComp));
      useDashboard.setDesignerLayerDropCompState({
        dragComp,
        index,
      });
    };

    /**
     * 拖动进入到移动节点
     */
    const moveDragEnter = (e: any, comp: any, index: number, isTop: boolean) => {
      const dragData = useDashboard.getDesignerLayerDropCompState;
      if (isTop) {
        //如果是上面的，必须是同一层并且在当前拖放对象前面
        e.target.className =
          dragData &&
          dragData.dragComp &&
          dragData.dragComp.level === comp.level &&
          dragData.index > index
            ? "hv-designer-layer-panel-move-item-enter"
            : "hv-designer-layer-panel-move-item";
      } else {
        //如果是上面的，必须是同一层并且在当前拖放对象后面
        e.target.className =
          dragData &&
          dragData.dragComp &&
          dragData.dragComp.level === comp.level &&
          dragData.index < index
            ? "hv-designer-layer-panel-move-item-enter"
            : "hv-designer-layer-panel-move-item";
      }
    };

    /**
     * 拖动离开到移动节点
     */
    const moveDragLeave = (e: any) => {
      e.target.className = "hv-designer-layer-panel-move-item";
    };

    /**
     * 拖动放下到移动节点
     */
    const moveDrop = (e: any, comp: any, index: number, isTop: boolean) => {
      e.target.className = "hv-designer-layer-panel-move-item";
      const dragData = useDashboard.getDesignerLayerDropCompState;
      //如果是上面的，必须是同一层并且在当前拖放对象前面
      if (
        isTop &&
        dragData &&
        dragData.dragComp &&
        dragData.dragComp.level === comp.level &&
        dragData.index > index
      ) {
        DashboardEvent.getLayerMoveToIndexEvent().next({
          dragComp: dragData.dragComp,
          targetIndex: index,
        });
        //如果是上面的，必须是同一层并且在当前拖放对象后面
      } else if (
        !isTop &&
        dragData &&
        dragData.dragComp &&
        dragData.dragComp.level === comp.level &&
        dragData.index < index
      ) {
        DashboardEvent.getLayerMoveToIndexEvent().next({
          dragComp: dragData.dragComp,
          targetIndex: index,
        });
      }
    };

    /**
     * 拖动放下
     */
    const drop = (e: any, dropComp: any) => {
      const dragCompData = e.dataTransfer.getData("dragComp");
      if (dragCompData && dragCompData.length > 0) {
        const dragComp = JSON.parse(dragCompData);

        // 拖动的组件与放置的是同一个组件或者拖动的是根组件
        if (
          dragComp.id === dropComp.id ||
          dragComp.id === layerPanelConfig.layerTreeRootNodeId
        ) {
          return;
        }

        // 当放置在组件上时
        if (dropComp.type === layerTreeNodeType.value.layer) {
          return;
        }

        // 拖动的是组件并且组件超过最大层级时
        if (
          dragComp.type === layerTreeNodeType.value.layer &&
          dropComp.level === layerPanelConfig.maxLevel
        ) {
          return;
        }

        // 拖动的是目录并且组件超过最大层级时
        if (
          dragComp.type === layerTreeNodeType.value.group &&
          dropComp.level === layerPanelConfig.maxLevel - 1
        ) {
          return;
        }

        // 拖动的是目录并且组件超过最大层级时
        if (
          dragComp.type == layerTreeNodeType.value.group &&
          getDepth(dragComp) + dropComp.level > layerPanelConfig.maxLevel - 1
        ) {
          return;
        }

        if (!(dropComp.children && dropComp.children.length > 0)) {
          dropComp.children = [];
        }

        const childrenLevel = dropComp.level + 1;
        const success = () => {
          dropComp.children.push({
            ...dragComp,
            level: childrenLevel,
          });
        };

        DashboardEvent.getDragLayerNodeEvent().next({
          dragComp,
          dropComp,
          success,
        });
      }
    };

    /**
     * 获取目录深度
     */
    const getDepth = (dropComp: any) => {
      let arr: any[] = [];
      arr.push(dropComp);
      let depth = 0;
      while (arr.length > 0) {
        let temp: any[] = [];
        for (let i = 0; i < arr.length; i++) {
          arr[i].type === layerTreeNodeType.value.group && temp.push(arr[i]);
        }
        arr = [];
        for (let i = 0; i < temp.length; i++) {
          if (
            temp[i] &&
            temp[i].children &&
            temp[i].type === layerTreeNodeType.value.group
          ) {
            for (let j = 0; j < temp[i].children.length; j++) {
              temp[i].children[j].type === layerTreeNodeType.value.group &&
                arr.push(temp[i].children[j]);
            }
          }
        }
        if (arr.length >= 0) {
          depth++;
        }
      }
      return depth;
    };

    const addLayerGroup = (comp: any) => {
      const group = {
        id: CommonUtil.shortUUID(),
        label: layerPanelConfig.groupComponent.label + CommonUtil.shortUUID(),
        img: layerPanelConfig.groupComponent.img,
        checked: false,
        type: layerTreeNodeType.value.group,
        open: true,
        level: comp.level + 1,
        children: [],
      };
      DashboardEvent.getAddSubLayerGroupEvent().next({
        parentComp: comp,
        newGroupComp: group,
      });
    };

    /**
     * 右健菜单事件
     */
    const contextmenuClick = ({ key }, comp: any) => {
      switch (key) {
        case "layerUp":
          DashboardEvent.getLayerUpEvent().next(comp);
          break;
        case "layerDown":
          DashboardEvent.getLayerDownEvent().next(comp);
          break;
        case "addLayerGroup":
          addLayerGroup(comp);
          break;
        case "layerToTop":
          DashboardEvent.getLayerToTopEvent().next(comp);
          break;
        case "layerToBottom":
          DashboardEvent.getLayerToBottomEvent().next(comp);
          break;
        case "layerCopy":
          DashboardEvent.getLayerCopyEvent().next({
            id: CommonUtil.shortUUID(),
            comp: cloneDeep(comp),
          });
          break;
        case "layerActive":
          DashboardEvent.getActiveCurrentLayerEvent().next(comp);
          break;
      }
    };

    /**
     * 切换子节点选择
     */
    const toggleChildrenNodeChecked = (comp: any, checkedState: boolean) => {
      if (comp.children && comp.children.length) {
        comp.children.map((node: any) => {
          node.checked = checkedState;
          toggleChildrenNodeChecked(node, checkedState);
        });
      }
    };

    /**
     * checkbox事件
     */
    const checkboxChange = (comp: any) => {
      //是根节点
      if (comp.id === layerTreeRootNodeId.value) {
        toggleChildrenNodeChecked(comp, comp.checked);
      } else {
        DashboardEvent.getLayerChildrenNodeCheckedEvent().next(true);
      }
    };

    /**
     * 标签编辑框切换
     */
    const editLabelInputToggle = (comp: any, edit: boolean) => {
      if (comp.id === layerTreeRootNodeId.value) {
        return;
      }
      comp.unstructuredData.isEditLabel = edit;
      //鼠标离开时修改组件名
      if (!edit) {
        DashboardEvent.getLayerRenameEvent().next(comp);
      }
    };

    return {
      layerTreeRootNodeId,
      layerTreeNodeType,
      maxLevel,
      layerPanelInfoStyle,
      dragstart,
      drop,
      moveDrop,
      moveDragEnter,
      moveDragLeave,
      contextmenuClick,
      checkboxChange,
      editLabelInputToggle,
    };
  },
});
</script>

<style lang="less" scoped>
@import "./DesignerLayerPanelNode.less";
</style>
